home *** CD-ROM | disk | FTP | other *** search
- /*-------------------------------------------------------------------
-
- AOCE Post Office Protocol (POP) / Simple Mail Transfer Protocol (SMTP)
- Mail Service Access Module
-
- written by Steve Falkenburg-- MacDTS
- ©1991-1993 Apple Computer, Inc.
-
- --------------
- change history
- --------------
-
- SJF 02/19/93 update for beta build b1
- SJF 10/29/92 update to a11 a11
- SJF 06/08/92 update to a8 a8
- SJF 02/15/92 first working version a4.5
- SJF 10/16/91 initial coding a3
-
- ---------------------------------------------------------------------*/
-
- #ifndef __TYPES__
- #include <Types.h>
- #endif
-
- #ifndef __PROCESSES__
- #include <Processes.h>
- #endif
-
- #ifndef __OCE__
- #include <OCE.h>
- #endif
-
- #ifndef __OCEERRORS__
- #include <OCEErrors.h>
- #endif
-
- #include "const.h"
- #include "gwerrors.h"
- #include "mytypes.h"
- #include "globals.h"
- #include "utils.h"
- #include "gatewaystuff.h"
- #include "gatewayget.h"
- #include "gatewayput.h"
- #include "errorhandling.h"
-
- #include "gatewayevents.h"
-
-
- // DoGatewayEvent
- //
- // handles high level events passed from the AOCE toolbox to the MSAM
- //
- // input: messageID -- identifies the high level event
- // mailEPPC -- mail EPPC message area containing shared mem area and msg seq number
- // slotID -- slot ID (if used)
- // inMainEventLoop -- true if we're being called from our main event loop
- //
- // on exit, the result field of the SMCA is set to the appropriate error code, indicating
- // that the MSAM is done processing the event
- //
- // note: I removed the EPPC handlers for MailboxOpened, MailboxClosed, and SendImmediate, as
- // they are no longer of value to the MSAM
- //
- // note: only CreateSlot, ModifySlot, DeleteSlot and message opened EPPCs are reliable
- // all others are informational only and may not always be sent (no guarantees)
- //
- // online gateway note: we do not handle kMailEPPCMsgOpened
- // since we are not an online gateway
- //
- OSErr DoGatewayEvent(long messageID,MailEPPCMsg *mailEPPC,short slotID,Boolean inMainEventLoop)
- {
- OSErr err;
-
- err = noErr;
-
- switch (messageID) {
-
- // create a new slot
- case kMailEPPCCreateSlot:
- err = CreateSlot(gMSAMCID,mailEPPC->u.theSMCA->u.slotCID);
- mailEPPC->u.theSMCA->result = err;
- break;
-
- // modify the contents of an existing slot
- case kMailEPPCModifySlot:
- err = ModifySlot(gMSAMCID,GetSlotSpecFromID(slotID),mailEPPC->u.theSMCA->u.slotCID);
- mailEPPC->u.theSMCA->result = err;
- break;
-
- // delete an existing slot
- case kMailEPPCDeleteSlot:
- err = DeleteSlot(gMSAMCID,GetSlotSpecFromID(slotID));
- mailEPPC->u.theSMCA->result = err;
- break;
-
- // shut down the gateway
- case kMailEPPCShutDown:
- err = ShutDownServer();
- break;
-
- // instructs the gateway to continue operation after previously suspending itself
- case kMailEPPCContinue:
- if (slotID==0)
- err = ContinueOperation(nil);
- else
- err = ContinueOperation(GetSlotSpecFromID(slotID));
- break;
-
- // informs a gateway that it's time to wake up (when a mail check timer expires)
- case kMailEPPCSchedule:
- if (inMainEventLoop)
- err = TimeToCheckForMail();
- else {
- err = EnqueueHighLevelEvent(kMailEPPCSchedule,nil,slotID);
- }
- break;
-
- // instructs a gateway to update its incoming queue (for post-its)
- //
- // CHANGE NOTE: you have to handle this EPPC even if you're not online, since
- // the appropriate action is to delete the message summary if the message is to be
- // deleted or at least set the msgUpdated field to false.
- //
- case kMailEPPCInQUpdate:
- if (inMainEventLoop)
- err = InQueueUpdate(mailEPPC->u.sequenceNumber,GetSlotSpecFromID(slotID),inMainEventLoop);
- else {
- err = EnqueueHighLevelEvent(kMailEPPCInQUpdate,mailEPPC,slotID);
- }
- break;
- // instructs a gateway that a message was opened (for post-its)
- case kMailEPPCMsgOpened:
- mailEPPC->u.theSMCA->result = noErr; // don't handle, since we're not online
- break;
-
- // instructs a gateway to wake up due to an external event (something bad happened)
- case kMailEPPCWakeup:
- err = WakeupFromExternalEvent();
- break;
-
- // notification that gateway has a letter in outgoing queue
- case kMailEPPCMsgPending:
- if (inMainEventLoop)
- err = MessagePending(GetSlotSpecFromID(slotID));
- else {
- err = EnqueueHighLevelEvent(kMailEPPCMsgPending,nil,slotID);
- }
- break;
-
- // send the message without waiting for the schedule event
- case kMailEPPCSendImmediate:
- // should save away sequence number to send now
- // also should force sending now…
- mailEPPC->u.theSMCA->result = noErr; // don't handle, since we're not online
- break;
-
- // tells us that the user changed the location info in "I'm at"
- case kMailEPPCLocationChanged:
- err = ChangeLocation(GetSlotSpecFromID(slotID),&mailEPPC->u.locationInfo);
- break;
-
- // these aren't handled
- case kMailEPPCMailboxOpened:
- case kMailEPPCMailboxClosed:
- case kMailEPPCDeleteOutQMsg:
- err = noErr;
- break;
-
- // unsupported high level event
- defaut:
- err = kUndefinedHighLevelEvent;
- break;
- }
-
- return err;
- }
-
-
- OSErr EnqueueHighLevelEvent(long messageID,MailEPPCMsg *mailEPPC,short slotID)
- {
- HLEventQ *newEl;
- MailEPPCMsg *newEPPC;
-
- newEl = NewPtrChk(sizeof(HLEventQ));
- if (MemError()!=noErr)
- return MemError();
-
- newEPPC = NewPtrChk(sizeof(MailEPPCMsg));
- if (MemError()!=noErr)
- return MemError();
- BlockMove(mailEPPC,newEPPC,sizeof(MailEPPCMsg));
-
- newEl->messageID = messageID;
- newEl->mailEPPC = newEPPC;
- newEl->slotID = slotID;
-
- newEl->next = gHLEventAdd;
- newEl->prev = nil;
- gHLEventAdd->prev = newEl;
- gHLEventAdd = newEl;
- if (gHLEventRemove==nil)
- gHLEventRemove = newEl;
-
- return noErr;
- }
-
-
- Boolean DequeueHighLevelEvent(long *messageID,MailEPPCMsg *mailEPPC,short *slotID)
- {
- HLEventQ *oldQ;
-
- if (!gHLEventRemove)
- return false;
-
- *messageID = gHLEventRemove->messageID;
- BlockMove(gHLEventRemove->mailEPPC,mailEPPC,sizeof(MailEPPCMsg));
- *slotID = gHLEventRemove->slotID;
-
- oldQ = gHLEventRemove;
- gHLEventRemove = gHLEventRemove->prev;
- if (gHLEventRemove)
- gHLEventRemove->next = nil;
- else
- gHLEventAdd = nil;
-
- DisposPtrChk(oldQ);
-
- return true;
- }
-
-
- OSErr ProcessQueuedEvents(void)
- {
- long messageID;
- MailEPPCMsg mailEPPC;
- short slotID;
- OSErr err;
-
- err = noErr;
- while (DequeueHighLevelEvent(&messageID,&mailEPPC,&slotID) && err==noErr) {
- err = DoGatewayEvent(messageID,&mailEPPC,slotID,true);
- }
- return err;
- }
-
-
- // CreateSlot
- //
- // high level call to process the Create Slot high level event
- //
- // inputs: msamCID -- creation ID of the MSAM setup record
- // slotCID -- creation ID of the new slot information
- //
- OSErr CreateSlot(CreationID msamCID,CreationID slotCID)
- {
- #pragma unused (msamCID)
- OSErr err;
- short slotID;
-
- TraceExecution("\pCreateSlot");
-
- // add SlotID to mailservice record
-
- slotID = 1; // we only have 1 slot for now, so it is always ID 1
-
- err = AddAttribute(&slotCID,gAOCESetupDSRef,OCEGetIndAttributeType(kSlotIDAttrTypeNum),
- &slotID,sizeof(short),typeBinary);
- if (err!=noErr)
- return err;
-
- MarkSlotInformationDirty(); // mark that slots need to be updated at main event time
- return noErr;
- }
-
-
- // ModifySlot
- //
- // high level call to process the Modify Slot high level event
- //
- // inputs: msamCID -- creation ID of the MSAM setup record
- // slot -- slot specifier for the slot being modified
- // slotCID -- creation ID of the modified slot information
- //
- OSErr ModifySlot(CreationID msamCID,SlotSpec *slot,CreationID slotCID)
- {
- #pragma unused (msamCID,slot,slotCID)
-
- TraceExecution("\pModifySlot");
-
- MarkSlotInformationDirty(); // mark that slots need to be updated at main event time
- return noErr;
- }
-
-
- // DeleteSlot
- //
- // high level call to process the Delete Slot high level event
- //
- // inputs: msamCID -- creation ID of the MSAM setup record
- // slot -- slot specifier for the slot being deleted
- //
- OSErr DeleteSlot(CreationID msamCID,SlotSpec *slot)
- {
- PackedRecordID packedAssocDir;
- AttributeCreationID attrCID;
- CreationID foundCID,*dirCID;
- AttributeCopyInfo attrInfo;
- OSErr err;
-
- #pragma unused(msamCID)
-
- TraceExecution("\pDeleteSlot");
-
- // ***NOTE***:
- //
- // we have to delete the entry we placed in the "aoce Directories" attribute in the setup
- // template at this point, since the system won't do it for us...
-
- // get associated directory creation ID
-
- err = GetSingleValueAttribute(&slot->slotCID,OCEGetIndAttributeType(kAssoDirectoryAttrTypeNum),
- &packedAssocDir,sizeof(PackedRecordID));
- if (err!=noErr)
- return err;
-
- // find directory CID value in oce setup directories attribute
-
- attrInfo.buffer = (Ptr)&packedAssocDir;
- attrInfo.bufferSize = packedAssocDir.dataLength + sizeof(short);
- err = GetParseAttributes(&gAOCESetupCID,kDirectoriesAttrTypeNum,SearchCallback,(long)&attrInfo);
- if (err!=noErr)
- return err;
-
- // delete this stray attribute
-
- err = DeleteSingleAttributeValue(&gAOCESetupCID,OCEGetIndAttributeType(kDirectoriesAttrTypeNum),
- &attrInfo.cid);
- if (err!=noErr)
- return err;
-
- // don't mark slots dirty, since we're about to reboot
- // instead set the # of slots to 0 and prepare to quit
- gNumSlots = 0;
-
- return noErr;
- }
-
-
- // ShutDownServer
- //
- // high level call to process the ShutDownServer high level event
- // sets gDone to true, indicating that we'll quit the next time through our event loop
- //
- OSErr ShutDownServer(void)
- {
- TraceExecution("\pShutDownServer");
-
- gDone = true;
- return noErr;
- }
-
-
- // MessagePending
- //
- // high level call to process the MessagePending high level event.
- // increments the number of messages pending counter on the slot the message is pending for.
- //
- OSErr MessagePending(SlotSpec *slot)
- {
- OSErr err;
-
- TraceExecution("\pMessagePending");
-
- // if the slot isn't suspended, do the send now
-
- if (slot && slot->enabled) {
- err = DoSlotGet(slot);
- if (err!=noErr)
- err = RetrySlotError(err,slot,false);
- }
-
- return err;
- }
-
-
- // ContinueOperation
- //
- // process continue high level event, which instructs a gateway to continue operation after
- // previously suspending itself. it's permissible to have a gateway quit itself between
- // transactions. if this is done, each time the gateway is launched, it will get a
- // continue eppc.
- //
- // input: slot contains the slot specification for the slot being resumed, or nil of
- // the continue applies to the entire gateway.
- //
- OSErr ContinueOperation(SlotSpec *slot)
- {
- TraceExecution("\pContinueOperation");
-
- if (slot)
- slot->enabled = true;
-
- return noErr;
- }
-
-
- // TimeToCheckForMail
- //
- // process schedule high level event, which is sent by the toolbox when the check for mail
- // timers specified in the slot configuration records expire. this event makes it so the
- // gateway doesn't continually have to poll to see if the checking timers have expired
- //
- OSErr TimeToCheckForMail(void)
- {
- OSErr err,err2;
-
- TraceExecution("\pTimeToCheckForMail");
-
- // do gets/puts for slots whose timers have expired
-
- err = PeriodicCheckGet();
- err2 = PeriodicCheckPut();
-
- if (err==noErr)
- err = err2;
-
- return err;
- }
-
-
- // InQueueUpdate
- //
- // process in queue update high level event which is sent by the toolbox to mark a message
- // read or to delete a message. this is mostly for on-line gateways, but we still need to
- // process it in our on-demand gateway, since the toolbox requires specific actions in response
- // to this event.
- //
- // we need to check the message summary for the message in question, and see if the msgDeleted
- // flag is true. if so, we should delete the message summary for the message.
- //
- // if not a delete, we need to set the msgUpdated field to false to indicate that we've
- // processed this event.
- //
- OSErr InQueueUpdate(long seqNum,SlotSpec *slot,Boolean inMainLoop)
- {
- MSAMParam gwp;
- MSAMMsgSummary msgSummary;
- OSErr err;
-
- TraceExecution("\pInQueueUpdate");
-
- if (!slot)
- return noErr;
-
- // get the message summary for the letter in question
-
- gwp.header.ioCompletion = (ProcPtr)MSAMCompletion;
- gwp.pmsamGetMsgSummary.inQueueRef = slot->inQueue;
- gwp.pmsamGetMsgSummary.seqNum = seqNum;
- gwp.pmsamGetMsgSummary.msgSummary = &msgSummary;
- gwp.pmsamGetMsgSummary.buffer = nil;
- gwp.pmsamGetMsgSummary.msgSummaryOffset = 0;
- err = PMSAMGetMsgSummary(&gwp,false); // changed from async to avoid re-entrancy problems
- if (err!=noErr)
- return err;
-
- // if the letter is marked for deletion, then delete the message summary
-
- if (msgSummary.msgDeleted) {
- gwp.msamDelete.queueRef = slot->inQueue;
- gwp.msamDelete.seqNum = seqNum;
- gwp.msamDelete.msgOnly = false;
- gwp.msamDelete.result = noErr;
- err = MSAMDelete(&gwp,false); // changed from async to avoid re-entrancy problems
- }
-
- // otherwise, set the message summary msgUpdated flag to false
- else {
- msgSummary.msgUpdated = false;
- err = PMSAMPutMsgSummary(&gwp,false);
- }
-
- return err;
- }
-
-
- // ChangeLocation
- //
- // refreshes the location settings and location activation settings for
- // the gateway's slots. this info is changed when the user chooses
- // "i'm at" from the Finder
- //
- OSErr ChangeLocation(SlotSpec *slot,MailLocationInfo *locationInfo)
- {
- TraceExecution("\pChangeLocation");
-
- gLocation = locationInfo->location;
- slot->locationActive = locationInfo->active;
- return noErr;
- }
-
-
- // WakeupFromExternalEvent
- //
- // process the wakeup high level event, which instructs a gateway to wake up due to
- // an external event that cannot be predicted by AOCE if a gateway receives an
- // eppcWakeup event just after being launched, it syhould take that to mean that it
- // was launched in response to an external event. if the gateway was al;ready running
- // when the event arrived, it is an indication that ian external event important to the
- // gateway has occured. the wakeup attempt is not reliable
- //
- OSErr WakeupFromExternalEvent(void)
- {
- TraceExecution("\pWakeupFromExternalEvent");
- return noErr;
- }
-